/*
 * $Id: $
 */
package org.rcgwt.client.ui.grid.controller;

import org.rcgwt.client.ui.grid.internal.IRenderedIndexRecorder;
import org.rcgwt.client.ui.grid.internal.IntRangeList;
import org.rcgwt.client.ui.grid.internal.model.IElementModel;
import org.rcgwt.client.ui.grid.internal.model.IGridModel;
import org.rcgwt.client.ui.grid.internal.model.IGroupModel;
import org.rcgwt.client.ui.grid.internal.model.IRowModel;
import org.rcgwt.client.ui.grid.internal.model.IViewModel;
import org.rcgwt.client.ui.grid.model.IGridWidget;
import org.rcgwt.client.ui.grid.provider.IFocusProvider;
import org.rcgwt.client.ui.grid.provider.IOverProvider;
import org.rcgwt.client.ui.grid.provider.ISelectionProvider;

import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.user.client.Event;

/**
 * 
 * @author Olivier Oeuillot (latest modification by $Author: $)
 * @version $Revision: $ $Date: $
 */
public class RowModelEventController implements IElementModelEventController {

	private int lastActivedRowModelIndex = -1; // Par défaut on commence en

	// haut !
	private boolean lastSelectionAppendMode = false;

	public boolean processFocus(IGridModelController gridModelController,
			IGridWidget gridWidget, IElementModel elementModel, Event event) {

		IFocusProvider focusProvider = gridWidget.getFocusProvider();
		if (focusProvider == null) {
			return false;
		}

		IGridModel gridModel = gridWidget.getGridModel();

		boolean selectRow = false;
		IRowModel rowModel = null;

		switch (elementModel.getType()) {
		case ROW:
			rowModel = (IRowModel) elementModel;
			break;

		case VIEW:

			rowModel = getLastActivedRowModel(gridModel, true);

			if (rowModel == null) {
				return false;
			}

			selectRow = true;
			break;

		default:
			return false;
		}

		IViewModel viewModel = DefaultGridController.getViewModel(gridWidget,
				event);

		focusProvider.setFocusElement(viewModel, rowModel);

		focusProvider.getFocus();

		if (selectRow) {
			selectRowModel(gridModelController, gridWidget, rowModel, event);
		}

		return true;
	}

	protected IRowModel getLastActivedRowModel(IGridModel gridModel,
			boolean computeDefaultOne) {
		if (lastActivedRowModelIndex >= 0) {
			IRowModel rowModel = gridModel
					.searchRowModel(lastActivedRowModelIndex);
			if (rowModel != null) {
				return rowModel;
			}
		}

		if (computeDefaultOne == false) {
			return null;
		}

		IRenderedIndexRecorder<IRowModel, IGroupModel> rowRenderedIndexRecorder = gridModel
				.getRowRenderedIndexRecorder();

		IRowModel rowModel = rowRenderedIndexRecorder
				.getElementModelByRenderedIndex(0);

		return rowModel;
	}

	protected void setLastActivedRowModel(IRowModel rowModel) {
		if (rowModel == null) {
			lastActivedRowModelIndex = -1;
			return;
		}
		lastActivedRowModelIndex = rowModel.getModelIndex();
	}

	@Override
	public boolean processBlur(IGridModelController gridModelController,
			IGridWidget gridWidget, IElementModel elementModel, Event event) {

		IFocusProvider focusProvider = gridWidget.getFocusProvider();
		if (focusProvider == null) {
			return false;
		}

		focusProvider.looseFocus();
		return true;
	}

	public boolean processOver(IGridModelController gridModelController,
			IGridWidget gridWidget, IElementModel elementModel, Event event) {
		IRowModel rowModel = DefaultGridController.getRowModel(elementModel);
		if (rowModel == null) {
			return false;
		}

		IOverProvider overProvider = gridWidget.getOverProvider();
		if (overProvider == null) {
			return true;
		}

		overProvider.setOverElement(rowModel);

		return true;
	}

	@Override
	public boolean processOut(IGridModelController gridModelController,
			IGridWidget gridWidget, IElementModel elementModel, Event event) {

		IOverProvider overProvider = gridWidget.getOverProvider();

		if (overProvider == null) {
			return true;
		}

		overProvider.setOverElement(null);

		return true;
	}

	public boolean processSelection(IGridModelController gridModelController,
			IGridWidget gridWidget, IElementModel elementModel, Event event) {
		IRowModel rowModel = DefaultGridController.getRowModel(elementModel);
		if (rowModel == null) {
			return false;
		}

		processSelection(gridWidget, rowModel, event);

		if (isFocusAutoSelect(gridWidget, event)) {
			processFocus(gridModelController, gridWidget, rowModel, event);
		}

		return true;
	}

	protected void processSelection(IGridWidget gridWidget, IRowModel rowModel,
			Event event) {

		ISelectionProvider selectionProvider = gridWidget
				.getSelectionProvider();

		IGridModel gridModel = gridWidget.getGridModel();

		int rowModelIndex = rowModel.getModelIndex();

		IRenderedIndexRecorder<IRowModel, IGroupModel> rowRenderedIndexRecorder = gridModel
				.getRowRenderedIndexRecorder();

		int rowRenderedIndex = rowRenderedIndexRecorder
				.getRenderedIndex(rowModel);

		boolean appendMode = isAppendMode(event);

		IRowModel lastSelection = getLastActivedRowModel(gridModel, false);

		if (isRangeMode(event) && lastSelection != null) {

			int startRenderedIndex = rowRenderedIndexRecorder
					.getRenderedIndex(lastSelection);
			int endRenderedIndex = rowRenderedIndex;

			// NON: lastSelectionRowRenderedIndex = rowModelIndex;

			if (startRenderedIndex > endRenderedIndex) {
				int inv = startRenderedIndex;
				startRenderedIndex = endRenderedIndex;
				endRenderedIndex = inv;
			}

			IntRangeList indexList = new IntRangeList();

			for (int index = startRenderedIndex; index <= endRenderedIndex; index++) {
				IRowModel rm = rowRenderedIndexRecorder
						.getElementModelByRenderedIndex(index);
				if (rm == null) {
					continue;
				}

				indexList.addIndex(rm.getModelIndex());
			}

			if (appendMode) {
				if (lastSelectionAppendMode) {
					// On deselectionne la liste ... et on selectionne le
					// selectionné

					indexList.remove(rowModelIndex);
					selectionProvider.clearSelection(indexList);

					if (selectionProvider.isRowSelected(rowModelIndex) == false) {
						selectionProvider.appendSelection(rowModelIndex);
					}

					return;
				}
				selectionProvider.appendSelection(indexList);
				return;
			}

			selectionProvider.setSelection(indexList);
			return;
		}

		setLastActivedRowModel(rowModel);
		lastSelectionAppendMode = appendMode;

		if (appendMode) {

			if (selectionProvider.isRowSelected(rowModelIndex)) {
				selectionProvider.clearSelection(rowModelIndex);
				return;
			}

			selectionProvider.appendSelection(rowModelIndex);
			return;
		}

		if (selectionProvider.isRowSelected(rowModelIndex)
				&& selectionProvider.getSelectionCount() == 1) {
			return;
		}

		selectionProvider.setSelection(rowModelIndex);
	}

	protected boolean isAppendMode(Event event) {
		return event.getCtrlKey();
	}

	protected boolean isRangeMode(Event event) {
		return event.getShiftKey();
	}

	@Override
	public boolean processKeyPress(IGridModelController gridModelController,
			IGridWidget gridWidget, IElementModel elementModel, Event event) {

		if (elementModel.getType() != IElementModel.Type.VIEW) {
			return false;
		}

		int keyCode = event.getKeyCode();

		IFocusProvider focusProvider = gridWidget.getFocusProvider();
		if (focusProvider == null) {
			return true;
		}

		IElementModel focusedElementModel = focusProvider
				.getFocusElementModel();

		IRenderedIndexRecorder<IRowModel, IGroupModel> rowRenderedIndexRecorder = gridWidget
				.getGridModel().getRowRenderedIndexRecorder();

		IRowModel focusedRowModel = null;
		int focusedRowRenderedIndex = -1;

		if (focusedElementModel != null
				&& focusedElementModel.getType() == IElementModel.Type.ROW) {
			focusedRowModel = (IRowModel) focusedElementModel;

			if (focusedRowModel != null) {
				focusedRowRenderedIndex = rowRenderedIndexRecorder
						.getRenderedIndex(focusedRowModel);
				if (focusedRowRenderedIndex < 0) {
					focusedRowModel = null;
				}
			}
		}

		switch (keyCode) {
		case KeyCodes.KEY_UP:
			if (focusedRowModel == null) {
				selectRowIndex(gridModelController, gridWidget, 0, event);
				cancelEvent(event);
				return true;
			}

			if (focusedRowRenderedIndex < 1) {
				cancelEvent(event);
				return true;
			}

			selectRowIndex(gridModelController, gridWidget,
					focusedRowRenderedIndex - 1, event);

			cancelEvent(event);
			return true;

		case KeyCodes.KEY_DOWN:
			if (focusedRowModel == null) {
				selectRowIndex(gridModelController, gridWidget, -1, event);
				cancelEvent(event);
				return true;
			}

			selectRowIndex(gridModelController, gridWidget,
					focusedRowRenderedIndex + 1, event);
			cancelEvent(event);
			return true;
		}

		return true;
	}

	protected void cancelEvent(Event event) {
		event.stopPropagation();
		event.preventDefault();
	}

	protected void selectRowIndex(IGridModelController gridModelController,
			IGridWidget gridWidget, int index, Event event) {
		if (index < 0) {
			// En partant du dernier !
			
			// TODO
			
			return;
		}

		IRowModel rowModel = gridWidget.getGridModel()
				.getRowRenderedIndexRecorder().getElementModelByRenderedIndex(
						index);

		selectRowModel(gridModelController, gridWidget, rowModel, event);
	}

	protected void selectRowModel(IGridModelController gridModelController,
			IGridWidget gridWidget, IRowModel rowModel, Event event) {
		if (rowModel == null) {
			return;
		}

		processFocus(gridModelController, gridWidget, rowModel, event);

		if (isFocusAutoSelect(gridWidget, event)) {
			processSelection(gridWidget, rowModel, event);
		}
	}

	protected boolean isFocusAutoSelect(IGridWidget gridWidget, Event event) {
		if (event.getCtrlKey() && event.getShiftKey() == false) {
			return false;
		}

		return gridWidget.isFocusAutoSelect();
	}
}
